<{extend name="Public:public" /}>

<{block name="title"}>插槽<{/block}>

<{block name="content"}> 
<div class="content guide with-sidebar components-slots-guide">
  
<h1>插槽</h1>
  
<h2 id="组件基础"> 
	<a href="#组件基础" class="headerlink" title="组件基础" data-scroll="">组件基础</a> 
</h2>
<p>此内容在原手册 组件基础中</p>
<p>和 HTML 元素一样，我们经常需要向一个组件传递内容，像这样：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">alert-box</span>&gt;</span></span><br><span class="line">  Something bad happened.</span><br><span class="line"><span class="tag">&lt;/<span class="name">alert-box</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>可能会渲染出这样的东西：</p>

<div id="slots-demo" class="demo"><div class="demo-alert-box"><strong>Error!</strong> 
    Something bad happened.
  </div></div>
<script>
Vue.component('alert-box', {
  template: '\
    <div class="demo-alert-box">\
      <strong>Error!</strong>\
      <slot></slot>\
    </div>\
  '
})
new Vue({ el: '#slots-demo' })
</script>
<style>
.demo-alert-box {
  padding: 10px 20px;
  background: #f3beb8;
  border: 1px solid #f09898;
}
</style>

<p>幸好，Vue 自定义的 <code>&lt;slot&gt;</code> 元素让这变得非常简单：</p>
<figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line">Vue.component(<span class="string">'alert-box'</span>, {</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div class="demo-alert-box"&gt;</span></span><br><span class="line"><span class="string">      &lt;strong&gt;Error!&lt;/strong&gt;</span></span><br><span class="line"><span class="string">      &lt;slot&gt;&lt;/slot&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span></span><br><span class="line">})</span><br></pre></td></tr></tbody></table></figure>
<p>如你所见，我们只要在需要的地方加入插槽就行了——就这么简单！</p>





<h2 id="插槽内容"> 
	<a href="#插槽内容" class="headerlink" title="插槽内容" data-scroll="">插槽内容</a> 
</h2> 
<p>Vue 实现了一套内容分发的 API，这套 API 基于当前的 <a href="https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md" target="_blank" rel="noopener">Web Components 规范草案</a>，将 <code>&lt;slot&gt;</code> 元素作为承载分发内容的出口。</p>
<p>它允许你像这样合成组件：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">navigation-link</span> <span class="attr">url</span>=<span class="string">"/profile"</span>&gt;</span></span><br><span class="line">  Your Profile</span><br><span class="line"><span class="tag">&lt;/<span class="name">navigation-link</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>然后你在 <code>&lt;navigation-link&gt;</code> 的模板中可能会写为：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:href</span>=<span class="string">"url"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">class</span>=<span class="string">"nav-link"</span></span></span><br><span class="line"><span class="tag">&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>当组件渲染的时候，这个 <code>&lt;slot&gt;</code> 元素将会被替换为“Your Profile”。插槽内可以包含任何模板代码，包括 HTML：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">navigation-link</span> <span class="attr">url</span>=<span class="string">"/profile"</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 添加一个 Font Awesome 图标 --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"fa fa-user"</span>&gt;</span><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">  Your Profile</span><br><span class="line"><span class="tag">&lt;/<span class="name">navigation-link</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>甚至其它的组件：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">navigation-link</span> <span class="attr">url</span>=<span class="string">"/profile"</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 添加一个图标的组件 --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">font-awesome-icon</span> <span class="attr">name</span>=<span class="string">"user"</span>&gt;</span><span class="tag">&lt;/<span class="name">font-awesome-icon</span>&gt;</span></span><br><span class="line">  Your Profile</span><br><span class="line"><span class="tag">&lt;/<span class="name">navigation-link</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>如果 <code>&lt;navigation-link&gt;</code> <strong>没有</strong>包含一个 <code>&lt;slot&gt;</code> 元素，则任何传入它的内容都会被抛弃。</p>
<h2 id="具名插槽"><a href="#具名插槽" class="headerlink" title="具名插槽" data-scroll="">具名插槽</a></h2><p>有些时候我们需要多个插槽。例如，一个假设的 <code>&lt;base-layout&gt;</code> 组件的模板如下：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">header</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 我们希望把页头放这里 --&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">header</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">main</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 我们希望把主要内容放这里 --&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">main</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">footer</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 我们希望把页脚放这里 --&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>对于这样的情况，<code>&lt;slot&gt;</code> 元素有一个特殊的特性：<code>name</code>。这个特性可以用来定义额外的插槽：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">header</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">slot</span> <span class="attr">name</span>=<span class="string">"header"</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">header</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">main</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">slot</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">main</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">footer</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">slot</span> <span class="attr">name</span>=<span class="string">"footer"</span>&gt;</span><span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>在向具名插槽提供内容的时候，我们可以在一个父组件的 <code>&lt;template&gt;</code> 元素上使用 <code>slot</code> 特性：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">base-layout</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">template</span> <span class="attr">slot</span>=<span class="string">"header"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Here might be a page title<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span>A paragraph for the main content.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span>And another one.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">template</span> <span class="attr">slot</span>=<span class="string">"footer"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>Here's some contact info<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">base-layout</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>另一种 <code>slot</code> 特性的用法是直接用在一个普通的元素上：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">base-layout</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">h1</span> <span class="attr">slot</span>=<span class="string">"header"</span>&gt;</span>Here might be a page title<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span>A paragraph for the main content.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span>And another one.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span> <span class="attr">slot</span>=<span class="string">"footer"</span>&gt;</span>Here's some contact info<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">base-layout</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>我们还是可以保留一个未命名插槽，这个插槽是<strong>默认插槽</strong>，也就是说它会作为所有未匹配到插槽的内容的统一出口。上述两个示例渲染出来的 HTML 都将会是：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">header</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Here might be a page title<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">header</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">main</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>A paragraph for the main content.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>And another one.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">main</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">footer</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>Here's some contact info<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<h2 id="插槽的默认内容"><a href="#插槽的默认内容" class="headerlink" title="插槽的默认内容" data-scroll="">插槽的默认内容</a></h2><p>有的时候为插槽提供默认的内容是很有用的。例如，一个 <code>&lt;submit-button&gt;</code> 组件可能希望这个按钮的默认内容是“Submit”，但是同时允许用户覆写为“Save”、“Upload”或别的内容。</p>
<p>你可以在组件模板里的 <code>&lt;slot&gt;</code> 标签内部指定默认的内容来做到这一点。</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">"submit"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">slot</span>&gt;</span>Submit<span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>如果父组件为这个插槽提供了内容，则默认的内容会被替换掉。</p>
<h2 id="编译作用域"><a href="#编译作用域" class="headerlink" title="编译作用域" data-scroll="">编译作用域</a></h2><p>当你想在插槽内使用数据时，例如：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">navigation-link</span> <span class="attr">url</span>=<span class="string">"/profile"</span>&gt;</span></span><br><span class="line">  Logged in as {{ user.name }}</span><br><span class="line"><span class="tag">&lt;/<span class="name">navigation-link</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>该插槽可以访问跟这个模板的其它地方相同的实例属性 (也就是说“作用域”是相同的)。但这个插槽<strong>不能</strong>访问 <code>&lt;navigation-link&gt;</code> 的作用域。例如尝试访问 <code>url</code> 是不会工作的。牢记一条准则：</p>
<blockquote>
<p>父组件模板的所有东西都会在父级作用域内编译；子组件模板的所有东西都会在子级作用域内编译。</p>
</blockquote>



<h2 id="作用域插槽"> 
	<a href="#作用域插槽" class="headerlink" title="作用域插槽" data-scroll="">作用域插槽</a> 
</h2> 
<blockquote>
	<p>2.1.0+ 新增 van: 一般用在子组件 遍历的情况</p>
</blockquote>

<p>有的时候你希望提供的组件带有一个可从子组件获取数据的可复用的插槽。例如一个简单的 <code>&lt;todo-list&gt;</code> 组件的模板可能包含了如下代码：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">li</span></span></span> <span class="tag"><span class="attr">v-for</span>=<span class="string">"todo in todos"</span></span><span class="tag"> <span class="attr">:key</span>=<span class="string">"todo.id"</span></span><span class="tag">&gt;</span> {{ todo.text }}<span class="tag">&lt;/<span class="name">li</span>&gt;</span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>但是在我们应用的某些部分，我们希望每个独立的待办项渲染出和 <code>todo.text</code> 不太一样的东西。这也是作用域插槽的用武之地。</p>
<p>为了让这个特性成为可能，你需要做的全部事情就是将待办项内容包裹在一个 <code>&lt;slot&gt;</code> 元素上，然后将所有和其上下文相关的数据传递给这个插槽：在这个例子中，这个数据是 <code>todo</code> 对象：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">li</span></span></span><span class="tag"> <span class="attr">v-for</span>=<span class="string">"todo in todos"</span></span><span class="tag"> <span class="attr">:key</span>=<span class="string">"todo.id"</span></span><span class="tag"> &gt;</span><br><span class="line">    <span class="comment">&lt;!-- 我们为每个 todo 准备了一个插槽，--&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 将 `todo` 对象作为一个插槽的 prop 传入。--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">slot</span> <span class="attr">:todo</span>=<span class="string">"todo"</span>&gt;</span></span><br><span class="line">      <span class="comment">&lt;!-- 回退的内容 --&gt;</span></span><br><span class="line">      {{ todo.text }}</span><br><span class="line">    <span class="tag">&lt;/<span class="name">slot</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>现在当我们使用 <code>&lt;todo-list&gt;</code> 组件的时候，我们可以选择为待办项定义一个不一样的 <code>&lt;template&gt;</code> 作为替代方案，并且可以通过 <code>slot-scope</code> 特性从子组件获取数据：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">todo-list</span> <span class="attr">:todos</span>=<span class="string">"todos"</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 将 `slotProps` 定义为插槽作用域的名字 --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">template</span> <span class="attr">slot-scope</span>=<span class="string">"slotProps"</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 为待办项自定义一个模板，--&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 通过 `slotProps` 定制每个待办项。--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span> <span class="attr">v-if</span>=<span class="string">"slotProps.todo.isComplete"</span>&gt;</span>✓<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    {{ slotProps.todo.text }}</span><br><span class="line">  <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">todo-list</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<blockquote>
<div><b>van:</b> todos传递给子组件 由子组件遍历 但每个遍历对象todo的操作 可以由父组件指定</div>
</blockquote>

<blockquote>
<p>在 2.5.0+，<code>slot-scope</code> 不再限制在 <code>&lt;template&gt;</code> 元素上使用，而可以用在插槽内的任何元素或组件上。</p>
</blockquote>
<h3 id="解构-slot-scope"><a href="#解构-slot-scope" class="headerlink" title="解构 slot-scope" data-scroll="">解构 <code>slot-scope</code></a></h3><p>如果一个 JavaScript 表达式在一个函数定义的参数位置有效，那么这个表达式实际上就可以被 <code>slot-scope</code> 接受。也就是说你可以在支持的环境下 (<a href="single-file-components.html">单文件组件</a>或<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#浏览器兼容" target="_blank" rel="noopener">现代浏览器</a>)，在这些表达式中使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#解构对象" target="_blank" rel="noopener">ES2015 解构语法</a>。例如：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">todo-list</span> <span class="attr">v-bind:todos</span>=<span class="string">"todos"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">template</span> <span class="attr">slot-scope</span>=<span class="string">"{ todo }"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span> <span class="attr">v-if</span>=<span class="string">"todo.isComplete"</span>&gt;</span>✓<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    {{ todo.text }}</span><br><span class="line">  <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">todo-list</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>这会使作用域插槽变得更干净一些。</p>

  
  
  
</div>
<{/block}>
